/*****************************************************************************
 * Copyright (C) Stacy Curl. All rights reserved.                            *
 * ------------------------------------------------------------------------- *
 * The software in this package is published under the terms of the BSD      *
 * style license a copy of which has been included with this distribution in *
 * the LICENSE.txt file.                                                     *
 *****************************************************************************/
package picounit.features.verify;

import picounit.Verify;
import picounit.features.aggregate_exception.Thrower;
import picounit.features.verify.constraint.Explanation;
import picounit.verify.BooleanArrayConstraints;
import picounit.verify.BooleanConstraints;
import picounit.verify.ByteArrayConstraints;
import picounit.verify.ByteConstraints;
import picounit.verify.CharacterArrayConstraints;
import picounit.verify.CharacterConstraints;
import picounit.verify.CollectionConstraints;
import picounit.verify.DoubleArrayConstraints;
import picounit.verify.DoubleConstraints;
import picounit.verify.ExtendedStringConstraints;
import picounit.verify.FileConstraints;
import picounit.verify.FloatArrayConstraints;
import picounit.verify.FloatConstraints;
import picounit.verify.IntegerArrayConstraints;
import picounit.verify.IntegerConstraints;
import picounit.verify.ListConstraints;
import picounit.verify.LongArrayConstraints;
import picounit.verify.LongConstraints;
import picounit.verify.SetConstraints;
import picounit.verify.ShortArrayConstraints;
import picounit.verify.ShortConstraints;
import picounit.verify.StringArrayConstraints;
import picounit.verify.TypedArrayConstraints;
import picounit.verify.TypedConstraints;
import picounit.verify.VerifyStage;

import java.io.File;
import java.util.Collection;
import java.util.List;
import java.util.Set;

import junit.framework.AssertionFailedError;

public class DefaultVerify extends Explanation implements Verify {
	private final CombinedConstraints constraints;
	private final Thrower thrower;
	
	public DefaultVerify(Evaluator evaluator, Thrower thrower, CombinedConstraints combinedConstraints) {
		super(evaluator);

		this.constraints = combinedConstraints;
		this.thrower = thrower;
	}
	
	///////////////////////////////////////////////////////////////////////////////////////////////
	// VerifyStage
	///////////////////////////////////////////////////////////////////////////////////////////////
	
	public VerifyStage because(String reason) {
		setReason(reason);

		return this;
	}

	public BooleanConstraints that(boolean value) {
		return constraints.constraintsFor(value);
	}
	
	public BooleanConstraints that(Boolean value) {
		return that(value.booleanValue());
	}
	
	public ByteConstraints that(byte value) {
		return constraints.constraintsFor(value);
	}
	
	public ByteConstraints that(Byte value) {
		return that(value.byteValue());
	}
	
	public CharacterConstraints that(char value) {
		return constraints.constraintsFor(value);
	}
	
	public CharacterConstraints that(Character value) {
		return that(value.charValue());
	}
	
	public DoubleConstraints that(double value) {
		return constraints.constraintsFor(value);
	}
	
	public DoubleConstraints that(Double value) {
		return that(value.doubleValue());
	}
	
	public FloatConstraints that(float value) {
		return constraints.constraintsFor(value);
	}
	
	public FloatConstraints that(Float value) {
		return that(value.floatValue());
	}
	
	public IntegerConstraints that(int value) {
		return constraints.constraintsFor(value);
	}
	
	public IntegerConstraints that(Integer value) {
		return that(value.intValue());
	}
	
	public LongConstraints that(long value) {
		return constraints.constraintsFor(value);
	}
	
	public LongConstraints that(Long value) {
		return that(value.longValue());
	}
	
	public ShortConstraints that(short value) {
		return constraints.constraintsFor(value);
	}
	
	public ShortConstraints that(Short value) {
		return that(value.shortValue());
	}
	
	public FileConstraints that(File value) {
		return constraints.constraintsFor(value);
	}
	
	public ExtendedStringConstraints that(String value) {
		return constraints.constraintsFor(value);
	}

	@SuppressWarnings("unchecked")
	public <T> TypedConstraints<T> that(T value) {
		return constraints.constraintsFor(value);
	}
	
	public BooleanArrayConstraints that(boolean ... value) {
		return constraints.constraintsFor(value);
	}
	
	public BooleanArrayConstraints that(Boolean... value) {
		return constraints.constraintsFor(toBooleans(value));
	}
	
	public ByteArrayConstraints that(byte ... value) {
		return constraints.constraintsFor(value);
	}
	
	public ByteArrayConstraints that(Byte... value) {
		return that(toBytes(value));
	}
	
	public CharacterArrayConstraints that(char ... value) {
		return constraints.constraintsFor(value);
	}
	
	public CharacterArrayConstraints that(Character... value) {
		return that(toChars(value));
	}
	
	public DoubleArrayConstraints that(double ... value) {
		return constraints.constraintsFor(value);
	}
	
	public DoubleArrayConstraints that(Double... value) {
		return that(toDoubles(value));
	}
	
	public FloatArrayConstraints that(float ... value) {
		return constraints.constraintsFor(value);
	}
	
	public FloatArrayConstraints that(Float... value) {
		return that(toFloats(value));
	}
	
	public IntegerArrayConstraints that(int ... value) {
		return constraints.constraintsFor(value);
	}
	
	public IntegerArrayConstraints that(Integer... value) {
		return that(toInts(value));
	}
	
	public LongArrayConstraints that(long ... value) {
		return constraints.constraintsFor(value);
	}
	
	public LongArrayConstraints that(Long... value) {
		return that(toLongs(value));
	}
	
	public ShortArrayConstraints that(short ... value) {
		return constraints.constraintsFor(value);
	}
	
	public ShortArrayConstraints that(Short... value) {
		return that(toShorts(value));
	}
	
	public StringArrayConstraints that(String ... value) {
		return constraints.constraintsFor(value);
	}
	
	@SuppressWarnings("unchecked")
	public <T> TypedArrayConstraints<T> that(T ... value) {
		return constraints.constraintsFor(value);
	}

	@SuppressWarnings("unchecked")
	public <T> CollectionConstraints<T> that(Collection<T> value) {
		return constraints.constraintsFor(value);
	}

	@SuppressWarnings("unchecked")
	public <T> ListConstraints<T> that(List<T> value) {
		return constraints.constraintsFor(value);
	}

	@SuppressWarnings("unchecked")
	public <T> SetConstraints<T> that(Set<T> value) {
		return constraints.constraintsFor(value);
	}
	
	///////////////////////////////////////////////////////////////////////////////////////////////
	// picounit.Verify
	///////////////////////////////////////////////////////////////////////////////////////////////

	public void fail() {
		thrower.errorEvent(new AssertionFailedError());
	}

	public void fail(String message) {
		thrower.errorEvent(new AssertionFailedError(message));
	}
	
	private boolean[] toBooleans(Boolean[] values) {
		boolean[] primatives = new boolean[values.length];
		
		for (int index = 0; index < primatives.length; index++ ) {
			primatives[index] = values[index].booleanValue();
		}
		
		return primatives;
	}
	
	private byte[] toBytes(Byte[] values) {
		byte[] primatives = new byte[values.length];
		
		for (int index = 0; index < primatives.length; index++ ) {
			primatives[index] = values[index].byteValue();
		}
		
		return primatives;
	}

	private char[] toChars(Character[] values) {
		char[] primatives = new char[values.length];
		
		for (int index = 0; index < primatives.length; index++ ) {
			primatives[index] = values[index].charValue();
		}
		
		return primatives;
	}

	private double[] toDoubles(Double[] values) {
		double[] primatives = new double[values.length];
		
		for (int index = 0; index < primatives.length; index++ ) {
			primatives[index] = values[index].doubleValue();
		}
		
		return primatives;
	}

	private float[] toFloats(Float[] values) {
		float[] primatives = new float[values.length];
		
		for (int index = 0; index < primatives.length; index++ ) {
			primatives[index] = values[index].floatValue();
		}
		
		return primatives;
	}

	private int[] toInts(Integer[] values) {
		int[] primatives = new int[values.length];
		
		for (int index = 0; index < primatives.length; index++ ) {
			primatives[index] = values[index].intValue();
		}
		
		return primatives;
	}

	private long[] toLongs(Long[] values) {
		long[] primatives = new long[values.length];
		
		for (int index = 0; index < primatives.length; index++ ) {
			primatives[index] = values[index].longValue();
		}
		
		return primatives;
	}

	private short[] toShorts(Short[] values) {
		short[] primatives = new short[values.length];
		
		for (int index = 0; index < primatives.length; index++ ) {
			primatives[index] = values[index].shortValue();
		}
		
		return primatives;
	}
}
